diff options
Diffstat (limited to 'app/[lng]/admin/edp/components/contract-items-form.tsx')
| -rw-r--r-- | app/[lng]/admin/edp/components/contract-items-form.tsx | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/app/[lng]/admin/edp/components/contract-items-form.tsx b/app/[lng]/admin/edp/components/contract-items-form.tsx new file mode 100644 index 00000000..ef8f09ef --- /dev/null +++ b/app/[lng]/admin/edp/components/contract-items-form.tsx @@ -0,0 +1,230 @@ +'use client' + +import { useState } from 'react' +import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' + +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' + +import { toast } from 'sonner' +import { createMultipleContractItems } from '../actions/contract-actions' +import { ContractSelector } from './contract-selector' +import { ItemSelector } from './item-selector' +import { Item } from '../types/item' +import { X } from 'lucide-react' + +interface Contract { + id: number + contractNo: string + contractName: string + status: string + projectId: number + vendorId: number + projectCode: string | null + projectName: string | null + vendorName: string | null + vendorCode: string | null +} + + + +interface SelectedItem { + itemId: number + ProjectNo: string + itemName: string + packageCode: string + itemCode: string | null + description?: string + quantity?: number + unitPrice?: number +} + +interface ContractItemsFormProps { + preselectedContractId?: number +} + +export function ContractItemsForm({ preselectedContractId }: ContractItemsFormProps) { + const [loading, setLoading] = useState(false) + const [selectedContract, setSelectedContract] = useState<Contract | undefined>() + const [selectedItems, setSelectedItems] = useState<SelectedItem[]>([]) + const [selectedItemIds, setSelectedItemIds] = useState<number[]>([]) + + // 아이템 선택 처리 + const handleItemsSelect = (itemIds: number[], itemsData?: Item[]) => { + setSelectedItemIds(itemIds) + + if (itemsData) { + // 새로운 아이템 데이터로 선택된 아이템 목록 업데이트 + const newSelectedItems: SelectedItem[] = itemsData.map(item => { + // 기존 선택된 아이템에서 수량, 단가, 설명 정보 유지 + const existing = selectedItems.find(selected => selected.itemId === item.id) + return { + itemId: item.id, + ProjectNo: item.ProjectNo, + itemName: item.itemName, + packageCode: item.packageCode, + itemCode: item.itemCode, + description: existing?.description || item.description || '', + quantity: existing?.quantity || 1, + unitPrice: existing?.unitPrice || 0 + } + }) + setSelectedItems(newSelectedItems) + } else { + // 기존 선택된 아이템들 중에서 새로 선택되지 않은 것들은 제거 + setSelectedItems(prev => prev.filter(item => itemIds.includes(item.itemId))) + } + } + + // 선택된 아이템 정보 반환 (이제 실제 데이터가 있음) + const getSelectedItemsWithDetails = (): SelectedItem[] => { + return selectedItems + } + + // 선택된 아이템 정보 업데이트 + const updateSelectedItem = (itemId: number, field: keyof SelectedItem, value: string | number) => { + setSelectedItems(prev => prev.map(item => + item.itemId === itemId ? { ...item, [field]: value } : item + )) + } + + // 선택된 아이템 제거 + const removeSelectedItem = (itemId: number) => { + setSelectedItemIds(prev => prev.filter(id => id !== itemId)) + setSelectedItems(prev => prev.filter(item => item.itemId !== itemId)) + } + + // 폼 제출 + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + if (!selectedContract) { + toast.error('계약을 선택해주세요.') + return + } + + if (selectedItemIds.length === 0) { + toast.error('최소 하나의 아이템을 선택해주세요.') + return + } + + setLoading(true) + try { + const currentSelectedItems = getSelectedItemsWithDetails() + const itemsData = currentSelectedItems.map(item => ({ + itemId: item.itemId, + description: item.description, + quantity: item.quantity || 1, + unitPrice: item.unitPrice || 0 + })) + + const result = await createMultipleContractItems(selectedContract.id, itemsData) + + if (result.success) { + toast.success(result.message) + setSelectedItems([]) + setSelectedItemIds([]) + } else { + toast.error(result.error) + } + } catch { + toast.error('계약 아이템 생성 중 오류가 발생했습니다.') + } finally { + setLoading(false) + } + } + + return ( + <Card> + <CardHeader> + <CardTitle>계약 아이템 생성</CardTitle> + <CardDescription> + 계약에 아이템들을 추가합니다. + </CardDescription> + </CardHeader> + <CardContent> + <form onSubmit={handleSubmit} className="space-y-6"> + {/* 계약 선택 */} + <div> + <Label>계약 선택 *</Label> + <ContractSelector + selectedContract={selectedContract} + onContractSelect={setSelectedContract} + disabled={loading} + preselectedContractId={preselectedContractId} + /> + </div> + + {/* 선택된 아이템 목록 */} + {selectedItemIds.length > 0 && ( + <div> + <Label>선택된 아이템 ({selectedItemIds.length}개)</Label> + <div className="mt-2 space-y-3 max-h-60 overflow-y-auto border rounded-md p-3"> + {getSelectedItemsWithDetails().map(item => ( + <div key={item.itemId} className="flex items-center gap-2 p-2 bg-gray-50 rounded"> + <div className="flex-1"> + <div className="font-medium text-sm"> + {item.itemName} {item.itemCode && `(${item.itemCode})`} + </div> + <div className="text-xs text-muted-foreground"> + 프로젝트: {item.ProjectNo} | 패키지: {item.packageCode} + </div> + <div className="flex gap-2 mt-1"> + <Input + type="number" + placeholder="수량" + value={item.quantity || ''} + onChange={(e) => updateSelectedItem(item.itemId, 'quantity', parseInt(e.target.value) || 1)} + className="w-20 h-8 text-xs" + /> + <Input + type="number" + placeholder="단가" + value={item.unitPrice || ''} + onChange={(e) => updateSelectedItem(item.itemId, 'unitPrice', parseFloat(e.target.value) || 0)} + className="w-24 h-8 text-xs" + /> + <Input + type="text" + placeholder="설명" + value={item.description || ''} + onChange={(e) => updateSelectedItem(item.itemId, 'description', e.target.value)} + className="flex-1 h-8 text-xs" + /> + </div> + </div> + <Button + type="button" + variant="ghost" + size="sm" + onClick={() => removeSelectedItem(item.itemId)} + > + <X className="h-4 w-4" /> + </Button> + </div> + ))} + </div> + </div> + )} + + {/* 아이템 선택 */} + <div> + <Label>아이템 선택</Label> + <div className="mt-1"> + <ItemSelector + selectedItems={selectedItemIds} + onItemsSelect={handleItemsSelect} + disabled={loading} + /> + </div> + </div> + + <Button type="submit" disabled={loading || selectedItemIds.length === 0} className="w-full"> + {loading ? '생성 중...' : `선택된 ${selectedItemIds.length}개 아이템 추가`} + </Button> + </form> + </CardContent> + </Card> + ) +} |
